package com.juzipi.demo.config;

import com.juzipi.demo.handler.*;
import com.juzipi.demo.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private MyUserDetailsService myUserDetailsService;

    //登陆成功
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    //登陆失败
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    //未登录
    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    //权限不足
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;
    //注销具体的操作
    @Autowired
    private MyLogoutHandler myLogoutHandler;
    //注销成功的处理
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;
    //超时管理
    @Autowired
    private MyInvalidSessionStrategy myInvalidSessionStrategy;
    //被挤下线的处理
    @Autowired
    private MySessionInformationExpiredStrategy mySessionInformationExpiredStrategy;


    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //任何请求都会被认证，所有的请求都会被拦截，包括登录
        http.authorizeRequests()
                //放行login
                .antMatchers("/login").permitAll()//登录允许所有
                //写死的
                /*.antMatchers("/user")
                .hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
                .antMatchers("/admin")
                .hasAnyAuthority("ROLE_ADMIN")*/
                //准备写活

                .anyRequest()
                .authenticated()
                //不加这个还真不行，自己给自己拦截了
                .and().formLogin()
                .successHandler(myAuthenticationSuccessHandler)//登陆成功处理
                .failureHandler(myAuthenticationFailureHandler)//登陆失败处理
                .and()
                //允许注销操作
                .logout().permitAll()
                .addLogoutHandler(myLogoutHandler)//添加自定义的注销操作
                .logoutSuccessHandler(myLogoutSuccessHandler)//注销成功
                .deleteCookies("JSESSIONID")//删除cookie
                //异常的处理
                .and().exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint)//用户未登录处理
                .accessDeniedHandler(myAccessDeniedHandler)//权限不足处理
                .and()
                //无状态的，任何时候都不会使用session
//                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//STATELESS: 无状态
                .sessionManagement().invalidSessionStrategy(myInvalidSessionStrategy)
                .maximumSessions(1)//最大允许登陆数量
                .maxSessionsPreventsLogin(false)//是否允许另一个账号登录
                //被挤下线的处理
                .expiredSessionStrategy(mySessionInformationExpiredStrategy);
        //暂时都不需要
                //设置登陆页面
//                .formLogin()
//                .loginPage("/login.html")
                //设置form表单的登陆控制器，默认是login
//                .loginProcessingUrl("/login")
                //输入框input的name名和password名 默认就是username 和 password
//                .usernameParameter("username")
//                .passwordParameter("password");

        //关闭跨域
        http.csrf().disable();
    }

    /**
     * 通过auth可以在内存中构建虚拟的用户名和密码
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这是之前写死的，方便对照着看
        /*auth.inMemoryAuthentication()
                .withUser("user")
                //密码加密了一下
                .password(passwordEncoder.encode("pass"))
                .roles("USER")
                .and()
                .withUser("admin")
                .password(passwordEncoder.encode("pass"))
                .roles("ADMIN")
                .and()
                //配置auth的加密方式为passwordEncoder
                .passwordEncoder(passwordEncoder);*/
        //写成活的
        auth.userDetailsService(myUserDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

}
